#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<assert.h>
#include<ctype.h>
#include<sys/stat.h>
#include<fcntl.h>

#define NUM 1024
#define OPT_NUM 64

#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3
#define delspace(start) do{\
    while(isspace(*start)) ++start;\
}while(0)

char linecommand[NUM];
char* myargv[OPT_NUM];
int lastcode=0;
int lastsig=0;

int redirtype=NONE_REDIR;
char* redirfile=NULL;

void commandcheck(char*commands)
{
    assert(commands);
    char* start=commands;
    char* end=commands+strlen(commands);
    while(start<end)
    {
        if(*start=='>')
        {
            *start='\0';
            ++start;
            if(*start=='>')
            {
                redirtype=APPEND_REDIR;
                ++start;
            }
            else
            {
                redirtype=OUTPUT_REDIR;
            }
            delspace(start);
            redirfile=start;
            break;
        }
        else if(*start=='<')
        {
            *start='\0';
            ++start;
            delspace(start);
            redirtype=INPUT_REDIR;
            redirfile=start;
            break;
        }
        else
            ++start;
    }
}

int main()
{
    while(1)
    {
        redirtype=NONE_REDIR;
        redirfile=NULL;

        printf("用户名@主机名 当前路径# ");
        fflush(stdout);

        char* s=fgets(linecommand,sizeof(linecommand)-1,stdin);
        assert(s!=NULL);
        (void)s;

        linecommand[strlen(linecommand)-1]=0;
        //printf("test:%s\n",linecommand);
        
        commandcheck(linecommand);
        
        myargv[0]=strtok(linecommand," ");
        int i=0;

        if(myargv[0]!=NULL&&strcmp(myargv[0],"ls")==0)
        {
            ++i;
            myargv[i]=(char*)"--color=auto";
        }

        while(myargv[i])
        {
            ++i;
            myargv[i]=strtok(NULL," ");
        }

        if(myargv[0]!=NULL&&strcmp(myargv[0],"cd")==0)
        {
            if(myargv[1]!=NULL)
                chdir(myargv[1]);
            continue;
        }


        if(myargv[0]!=NULL&&strcmp(myargv[0],"echo")==0)
        {
            if(strcmp(myargv[1],"$?")==0)
            {
                printf("%d  %d\n",lastcode,lastsig);
            }
            continue;
        }



#ifdef DEBUG

    for(int i=0;myargv[i];i++)
    {
        printf("myargv[%d]:%s\n",i,myargv[i]);
    }

#endif
    pid_t id=fork();
    assert(id!=-1);
    if(id==0)
    {
        switch(redirtype)
        {
            case NONE_REDIR:
                break;
            case INPUT_REDIR:
                {
                    int fd=open(redirfile,O_RDONLY);
                    if(fd<0)
                    {
                        perror("open");
                        return 1;
                    }
                    dup2(fd,0);
                }
                break;
            case OUTPUT_REDIR:
            case APPEND_REDIR:
                {
                    int flags=O_WRONLY|O_CREAT;
                    if(redirtype==OUTPUT_REDIR)
                    {
                        flags|=O_TRUNC;
                    }
                    else
                    {
                        flags|=O_APPEND;
                    }
                    int fd=open(redirfile,flags,0666);
                    if(fd<0)
                    {
                        perror("open");
                        return 1;
                    }
                    dup2(fd,1);
                }
                break;
            default:
                printf("bug\n");
                break;
        }

        execvp(myargv[0],myargv);
        exit(1);
    }

    int status=0;
    pid_t ret=waitpid(id,&status,0);
    assert(ret>0);
    (void)ret;
    lastcode=((status>>8)&0xFF);
    lastsig=(status&0x7F);

    }   
}
